<script setup lang="ts">

import {
  DataTableBaseColumn,
  type DataTableColumns,
  DataTableFilterState,
  FormInst,
  FormItemRule,
  FormRules,
  NButton,
  NButtonGroup,
  NSpace,
  PaginationInfo,
  PaginationProps,
  TransferOption
} from "naive-ui";
import {useDictStore} from "@/stores";
import {SysUser} from "@/api/user/types.ts";
import {renderPermission, resetToNull} from "@/utils";
import {userApi} from "@/api/user";
import {roleApi} from "@/api/role";
import {useRoute} from "vue-router";

enum ModeTypeEnum {
  ADD = '新增',
  MODIFY = '修改',
  DETAIL = '详情'
}

interface PageQuery {
  deptId: string
  keyword: string
  userStatus: number
}

const dictStore = useDictStore();
const currentRoute = useRoute();
const pageQuery = reactive<PageQuery>(<PageQuery>{})
const tableLoading = ref(false);
// @ts-ignore
const tableColumns = ref<DataTableColumns<SysUser>>([
  {title: '用户名', key: 'username', resizable: true},
  {title: '用户昵称', key: 'nickname', resizable: true},
  {
    title: '用户状态',
    key: 'userStatus',
    resizable: true,
    render: row => dictStore.renderTag('common-status', row.userStatus),
    filter: true,
    filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('common-status')
  },
  {title: '创建时间', key: 'createTime', resizable: true},
  {title: '最后登录时间', key: 'lastLoginTime', resizable: true},
  {title: '最后登录IP', key: 'lastLoginIp', resizable: true},
  {title: '操作', key: 'action', align: 'center', render: row => tableActionRender(row)}
])
const tableData = ref<SysUser[]>([])
const tablePagination = reactive<PaginationProps>({
  prefix: (info: PaginationInfo) => {
    return `共 ${info.itemCount} 条记录`
  },
  showSizePicker: true,
  pageSizes: [10, 20, 50, 100],
  itemCount: 0,
  pageCount: 0,
  onChange: (page: number) => {
    tablePagination.page = page
    handlePageQuery()
  },
  onUpdatePageSize: (pageSize: number) => {
    tablePagination.pageSize = pageSize
    tablePagination.page = 1
    handlePageQuery()
  }
})

const drawerDetailShow = ref(false)
const drawerDetailTitle = ref()
const drawerDetailFormRef = ref<FormInst | null>(null)
const drawerDetailSubmitLoading = ref(false)
const drawerDetailFormRules = reactive<FormRules>({
  username: {
    required: true,
    trigger: ['change', 'blur'],
    validator: (rule: FormItemRule, value: string) => {
      if (!value) {
        return new Error('用户名不能为空')
      } else if (value.length > 20 || value.length < 8) {
        return new Error('用户名长度必须在8-20之间')
      }
    }
  },
  nickname: {
    required: true,
    trigger: ['change', 'blur'],
    validator: (rule: FormItemRule, value: string) => {
      if (!value) {
        return new Error('昵称不能为空')
      } else if (value.length > 20 || value.length < 2) {
        return new Error('昵称长度必须在2-20之间')
      }
    }
  },
  userStatus: {required: true, message: '请选择状态', type: 'number', trigger: 'blur'}
})
const drawerDetailFormModel = reactive<SysUser>(<SysUser>{})

const modalGrantShow = ref(false)
const modalGrantEntity = reactive<SysUser>({})
const modalGrantOptions = ref<TransferOption[]>([])
const modalGrantChecked = ref<string[]>([])
const modalGrantLoading = ref(false)

onMounted(() => {
  dictStore.loadDict(['common-status'])
  initUserTable()
})

watch(() => currentRoute.query, () => {
  initUserTable()
})

const initUserTable = () => {
  if (currentRoute.query.deptId && currentRoute.query.deptId !== pageQuery.deptId) {
    pageQuery.deptId = currentRoute.query.deptId as string
  } else {
    pageQuery.deptId = ''
  }
  handlePageQuery()
}

const tableActionRender = (row: SysUser) => {
  return h(NButtonGroup, {size: 'small'}, {
    default: () => [
      renderPermission(h(NButton, {
        tertiary: true,
        onClick: () => handleClickDetail(row)
      }, {default: () => '详情'}), 'user:detail'),
      renderPermission(h(NButton, {
        tertiary: true,
        type: 'primary',
        onClick: () => handleClickModify(row)
      }, {default: () => '修改'}), 'user:modify'),
      renderPermission(h(NButton, {
        tertiary: true,
        type: 'info',
        onClick: () => handleClickGrant(row)
      }, {default: () => '授权'}), 'user:grant')
    ]
  })
}

const handlePageQuery = () => {
  tableLoading.value = true
  userApi.page({
    ...pageQuery,
    current: tablePagination.page ?? 1,
    size: tablePagination.pageSize ?? 10
  }).then(res => {
    tableData.value = res.data.records
    tablePagination.itemCount = res.data.total
    tablePagination.pageCount = res.data.pages
  }).finally(() => tableLoading.value = false)
}

const initDrawerDetail = (type: ModeTypeEnum) => {
  drawerDetailShow.value = true
  drawerDetailTitle.value = type
}

const handleClickAdd = () => {
  initDrawerDetail(ModeTypeEnum.ADD)
  drawerDetailFormModel.userStatus = dictStore.getDictDefault('common-status').dictValue as number
}
const handleClickDetail = (row: SysUser) => {
  if (row.id != null) {
    userApi.detail(row.id).then(res => {
      Object.assign(drawerDetailFormModel, res.data)
      initDrawerDetail(ModeTypeEnum.DETAIL)
    })
  }
}
const handleClickModify = (row: SysUser) => {
  if (row.id != null) {
    userApi.detail(row.id).then(res => {
      Object.assign(drawerDetailFormModel, res.data)
      initDrawerDetail(ModeTypeEnum.MODIFY)
    })
  }
}
const handleDrawerClose = () => {
  drawerDetailShow.value = false
  resetToNull(drawerDetailFormModel)
  handlePageQuery()
}
const handleClickSubmit = () => {
  drawerDetailSubmitLoading.value = true
  drawerDetailFormRef.value?.validate((errors) => {
    if (!errors) {
      switch (drawerDetailTitle.value) {
        case ModeTypeEnum.ADD:
          userApi.add(drawerDetailFormModel).then(res => {
            window.$message?.success(res.message)
            drawerDetailShow.value = false
          })
          break;
        case ModeTypeEnum.MODIFY:
          userApi.modify(drawerDetailFormModel).then(res => {
            window.$message?.success(res.message)
            drawerDetailShow.value = false
          })
      }
    }
  }).finally(() => drawerDetailSubmitLoading.value = false)
}
const handleClickGrant = (row: SysUser) => {
  modalGrantShow.value = true
  Object.assign(modalGrantEntity, row)
  roleApi.list({status: 1}).then(res => {
    modalGrantOptions.value = res.data.map(i => {
      return {
        label: `${i.roleName} | ${i.roleCode}`,
        value: i.id
      } as TransferOption
    })
  })
  if (row.id) {
    userApi.grantedList(row.id).then(res => {
      modalGrantChecked.value = res.data.roleIds
    })
  }
}
const handleModalGrantClose = () => {
  modalGrantLoading.value = false
  modalGrantShow.value = false
  modalGrantOptions.value = []
  modalGrantChecked.value = []
  resetToNull(modalGrantEntity)
}
const handleClickGrantSubmit = () => {
  modalGrantLoading.value = true
  userApi.grant({id: modalGrantEntity.id, roleIds: modalGrantChecked.value}).then(res => {
    window.$message?.success(res.message)
    modalGrantShow.value = false
    handlePageQuery()
  }).finally(() => modalGrantLoading.value = false)
}
</script>

<template>
  <n-card class="user-manage" flex-1 h-fit>
    <template #header>
      <n-space>
        <n-input v-model:value="pageQuery.keyword" placeholder="角色名称/角色编码" clearable/>
        <n-button
            secondary
            @click="handlePageQuery"
            :loading="tableLoading"
            v-p="'user:page'"
        >查询
        </n-button>
        <n-button
            secondary
            type="primary"
            @click="handleClickAdd"
            v-p="'user:add'"
        >新增
        </n-button>
      </n-space>
    </template>
    <n-data-table
        remote
        :loading="tableLoading"
        :columns="tableColumns"
        :data="tableData"
        :pagination="tablePagination"
        @update:filters="(filters: DataTableFilterState, {key}: DataTableBaseColumn) => {
          pageQuery[key] = filters[key]
          handlePageQuery()
        }"
    />
  </n-card>
  <n-drawer
      v-model:show="drawerDetailShow"
      :width="400"
      placement="right"
      :on-after-leave="handleDrawerClose"
      :auto-focus="false"
      :mask-closable="false"
      close-on-esc
  >
    <n-drawer-content :title="drawerDetailTitle" closable>
      <n-form
          ref="drawerDetailFormRef"
          :model="drawerDetailFormModel"
          :rules="drawerDetailFormRules"
          :disabled="drawerDetailTitle === ModeTypeEnum.DETAIL"
      >
        <n-grid :cols="24" :x-gap="12">
          <n-form-item-gi v-if="drawerDetailFormModel.id" :span="24" label="主键">
            <n-tag type="primary">{{ drawerDetailFormModel.id }}</n-tag>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="用户名" path="username">
            <n-input v-model:value="drawerDetailFormModel.username" placeholder="请输入用户名" clearable/>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="昵称" path="nickname">
            <n-input v-model:value="drawerDetailFormModel.nickname" placeholder="请输入昵称" clearable/>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="状态" path="userStatus">
            <n-select
                v-model:value="drawerDetailFormModel.userStatus"
                :options="dictStore.getDictTagOptions('common-status')"
                placeholder="请选择状态"
                clearable
            />
          </n-form-item-gi>
        </n-grid>
      </n-form>
      <template v-if="drawerDetailTitle !== ModeTypeEnum.DETAIL" #footer>
        <n-button secondary type="primary" @click="handleClickSubmit" :loading="drawerDetailSubmitLoading">提交
        </n-button>
      </template>
    </n-drawer-content>
  </n-drawer>
  <n-modal
      :on-after-leave="handleModalGrantClose"
      v-model:show="modalGrantShow"
      title="用户授权"
      w-600px
      close-on-esc
      closable
      preset="card"
      :auto-focus="false"
      :mask-closable="false"
      footer-class="text-align-right"
  >
    <n-transfer v-model:value="modalGrantChecked" :options="modalGrantOptions"/>
    <template #footer>
      <n-button secondary type="primary" @click="handleClickGrantSubmit" :loading="modalGrantLoading">提交</n-button>
    </template>
  </n-modal>
</template>

<style scoped>

</style>